/*
 * Porting to u-boot:
 *
 * (C) Copyright 2014
 * TangHaifeng <tanghaifeng-gz@loongson.cn>
 *
 * SPDX-License-Identifier:	GPL-2.0+
 */

#include <common.h>
#include <linux/list.h>
#include <linux/fb.h>
#include <ipu_pixfmt.h>

#include <asm/io.h>
#include <asm/gpio.h>
#include <asm/arch/ls2k.h>
#include <asm/arch-loongson1/ls1xfb.h>

#if defined(CONFIG_SII9022A)
#include "sii9022a.h"
#endif

enum panel_dev {
	PANEL_DEV_UNKNOWN = 0,
	PANEL_AT043TN13,
	PANEL_HX8264,
	PANEL_VESA800X600_60,
	PANEL_VESA1024X768_60,
	PANEL_VESA1280X720_60,
	PANEL_VESA1280X1024_60,
	PANEL_VESA1440X900_75,
	PANEL_VESA1920X1080_60,
	PANEL_DEV_COUNT,			/* Number of dev types */
};

static struct fb_videomode panel[] = {
[PANEL_AT043TN13] = {
	.name	= "at043tn13",
	.pixclock	= 111000,
	.refresh	= 60,
	.xres		= 480,
	.yres		= 272,
	.hsync_len	= 41,		// 523-482
	.left_margin	= 2,	// 525-523
	.right_margin	= 2,	// 482-480
	.vsync_len	= 10,		// 284-274
	.upper_margin	= 4,	// 288-284
	.lower_margin	= 2,	// 274-272
	.sync		= FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
	},
[PANEL_HX8264] = {
	.name	= "at070tn93",	// AT070TN93
	.pixclock	= 34209,
	.refresh	= 60,
	.xres		= 800,
	.yres		= 480,
	.hsync_len	= 48,		// 888-840
	.left_margin	= 40,	// 928-888
	.right_margin	= 40,	// 840-800
	.vsync_len	= 3,		// 496-493
	.upper_margin	= 29,	// 525-496
	.lower_margin	= 13,	// 493-480
	.sync		= FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
	},
[PANEL_VESA800X600_60] = {	//VESA 800x600@60Hz
	.name	= "vesa800x600@60",
	.pixclock	= 25000,
	.refresh	= 60,
	.xres		= 800,
	.yres		= 600,
	.hsync_len	= 128,		// 896-816
	.left_margin	= 88,	// 1056-896
	.right_margin	= 40,	// 816-800
	.vsync_len	= 4,		// 484-481
	.upper_margin	= 23,	// 500-484
	.lower_margin	= 1,	// 481-480
	.sync		= FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
	},
[PANEL_VESA1024X768_60] = {	//VESA 1024x768@60Hz
	.name	= "vesa1024x768@60",
	.pixclock	= 15384,
	.refresh	= 60,
	.xres		= 1024,
	.yres		= 768,
	.hsync_len	= 136,		// 896-816
	.left_margin	= 160,	// 1056-896
	.right_margin	= 24,	// 816-800
	.vsync_len	= 6,		// 484-481
	.upper_margin	= 29,	// 500-484
	.lower_margin	= 3,	// 481-480
	.sync		= FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
	},
[PANEL_VESA1280X720_60] = {	//VESA 1280x720@60Hz
	.name	= "vesa1280x720@60",
	.pixclock	= 13468,
	.refresh	= 60,
	.xres		= 1280,
	.yres		= 720,
	.hsync_len	= 40,
	.left_margin	= 220,
	.right_margin	= 110,
	.vsync_len	= 5,
	.upper_margin	= 20,
	.lower_margin	= 5,
	.sync		= FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
	},
[PANEL_VESA1280X1024_60] = {	//VESA 1280x1024@60Hz
	.name	= "vesa1280x1024@60",
	.pixclock	= 9259,
	.refresh	= 60,
	.xres		= 1280,
	.yres		= 1024,
	.hsync_len	= 112,
	.left_margin	= 248,
	.right_margin	= 48,
	.vsync_len	= 3,
	.upper_margin	= 38,
	.lower_margin	= 1,
	.sync		= FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
	},
[PANEL_VESA1440X900_75] = {	//VESA 1440x900@75Hz
	.name	= "vesa1400x900@75",
	.pixclock	= 7312,
	.refresh	= 75,
	.xres		= 1440,
	.yres		= 900,
	.hsync_len	= 152,
	.left_margin	= 248,
	.right_margin	= 96,
	.vsync_len	= 6,
	.upper_margin	= 33,
	.lower_margin	= 3,
	.sync		= FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
	},
[PANEL_VESA1920X1080_60] = {	//VESA 1920x1080@60Hz
	.name	= "vesa1920x1080@60",
	.pixclock	= 6734,
	.refresh	= 60,
	.xres		= 1920,
	.yres		= 1080,
	.hsync_len	= 44,
	.left_margin	= 148,
	.right_margin	= 88,
	.vsync_len	= 5,
	.upper_margin	= 36,
	.lower_margin	= 4,
	.sync		= FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
	},
};

struct ls1xfb_mach_info ls1x_lcd0_info = {
	.base		= CKSEG1ADDR(LS2X_DC0_BASE),
	.id			= "Graphic lcd",
	.modes			= (struct fb_videomode *)&panel[PANEL_VESA800X600_60],
//	.num_modes		= ARRAY_SIZE(video_modes),
	.pix_fmt		= PIX_FMT_RGB565,
	.de_mode		= 0,	/* 注意：lcd是否使用DE模式 */
	/* 根据lcd屏修改invert_pixclock和invert_pixde参数(0或1)，部分lcd可能显示不正常 */
	.invert_pixclock	= 0,
	.invert_pixde	= 0,
};

struct ls1xfb_mach_info ls1x_lcd1_info = {
	.base		= CKSEG1ADDR(LS2X_DC1_BASE),
	.id			= "Graphic vga",
	.modes			= (struct fb_videomode *)&panel[PANEL_VESA800X600_60],
//	.num_modes		= ARRAY_SIZE(video_modes),
	.pix_fmt		= PIX_FMT_RGB565,
	.de_mode		= 0,	/* 注意：lcd是否使用DE模式 */
	/* 根据lcd屏修改invert_pixclock和invert_pixde参数(0或1)，部分lcd可能显示不正常 */
	.invert_pixclock	= 0,
	.invert_pixde	= 0,
};

static void backlight(int on)
{
}

int board_video_skip(void)
{
	struct ls1xfb_mach_info *info;
	struct fb_videomode *videomode;
	int dev = PANEL_DEV_UNKNOWN;
	int ret;
	char const *e = NULL;

#if defined(CONFIG_LS1X_DC0)
	info = &ls1x_lcd0_info;
	#if defined(CONFIG_LS1X_DC0_USE_DEMODE)
	info->de_mode = 1;
	#endif
#elif defined(CONFIG_LS1X_DC1)
	info = &ls1x_lcd1_info;
	#if defined(CONFIG_LS1X_DC1_USE_DEMODE)
	info->de_mode = 1;
	#endif
#endif

	e = getenv("panel");
	if (e) {
		for (dev = 0; dev < PANEL_DEV_COUNT; dev++) {
			videomode = (struct fb_videomode *)&panel[dev];
			if (videomode->name && !strcmp(e, videomode->name)) {
				break;
			}
		}
	}

	if (dev == PANEL_DEV_COUNT || e == NULL) {
		videomode = (struct fb_videomode *)&panel[PANEL_VESA800X600_60];
	}

	ret = ls1x_fb_init(videomode, 0, IPU_PIX_FMT_RGB565, info);
	if (ret)
		printf("Panel cannot be configured: %d\n", ret);
	/* 背光使能，放在此处可能会导致启动过程中显示屏花屏，应该放在加载完logo再使能背光 */
//	backlight(1);
#if defined(CONFIG_SII9022A)
	sii9022a_set_dvi_encoder();
#endif

	return ret;
}

ulong video_setmem(ulong addr)
{
	ulong size;
	int i;

#ifdef DEFAULT_FB_SIZE
	size = DEFAULT_FB_SIZE;
#else
	size = SZ_8M;
#endif

	/* Round up to nearest full page, or MMU section if defined */
	size = ALIGN(size, ARCH_DMA_MINALIGN);
	addr = ALIGN(addr - ARCH_DMA_MINALIGN + 1, ARCH_DMA_MINALIGN);

	/* Allocate pages for the frame buffer. */
	addr -= size;

	debug("Reserving %ldk for Video Framebuffer at: %08lx\n",
	      size >> 10, addr);

	return addr;
}
